import ErrorStackParser from 'error-stack-parser'
import { record } from 'rrweb'

// 错误有很多种类型,这时候只能具体情况具体的逻辑了
// 监听普通的错误事件
export function trackError() {
  const global = this
  if(!global.options.trackError){ return }
  global.allErrors = []  // 用来存储所有错误对象的数组,进行错误去重
  // 1.js执行错误,第三个参数设置为false或者为true都可以捕捉到,注意返回的属性名
  window.addEventListener('error', (e) => {
    const { filename, lineno, colno, message } = e
    global.sendDataBefore([], 'error', { errorType: 'jsError', message, fileName: filename, columnNumber: colno, lineNumber: lineno })  // 上报
  }, false)
  // 2.资源加载错误,第三个参数设置为true才可以捕捉的到,所以为了避免重复要区分两个来捕捉,resourceError是没有message属性的
  window.addEventListener('error', (e) => {
    // 过滤js的error
    const target = e.target
    const isElementTarget = target instanceof HTMLScriptElement || target instanceof HTMLLinkElement || target instanceof HTMLImageElement
    if (!isElementTarget) return false
    // 上报资源地址
    const url = target.src || target.href
    global.sendDataBefore([], 'error', { errorType: 'resourceError', url })  // 上报
  }, true)
  // 3.未处理的promise错误,我们需要的三个参数都在reason对象的stack属性里
  window.addEventListener('unhandledrejection', e => {
    // at http://127.0.0.1:5508/%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81.html:94:21
    const matchResult = e.reason.stack.match(/(.+)\s+at\s+(.+):(\d+):(\d+)/)
    global.sendDataBefore([], 'error', { errorType: 'promiseError', fileName: matchResult[2], columnNumber: matchResult[4], lineNumber: matchResult[3], message: matchResult[1] })  // 上报
  })
}

// 监听当页面框架特有的错误事件,注意返回的属性名
// 4.监听Vue特有的错误处理
export function trackVueError(Vue, global) {
  if(!global.options.trackError){ return }
  const beforeErrorHandler = Vue.config.errorHandler
  Vue.config.errorHandler = function (e) {
    console.error(e)
    const errorTrack = ErrorStackParser.parse(e)[0]  // 返回的记录是看不到第几行代码的,只能依赖第三方包
    const { fileName, columnNumber, lineNumber } = errorTrack
    global.sendDataBefore([], 'error', { errorType: 'VueError', fileName, columnNumber, lineNumber, message: String(e) })
    if(beforeErrorHandler) beforeErrorHandler.apply(this,arguments)
  }
}

// 开启录屏,方便查看报错的前后过程
export function recordFunc() {
  const global = this
  if(!global.options.trackError){ return }
  if (global.options.openErrorRecord) {
    global.consoleLog('开始录屏')
    // events存储录屏信息
    global.events = []
    // record 用于记录DOM中的所有变更
    record({
      emit(event, isCheckout) {
        // isCheckout 是一个标识，告诉你重新制作了快照
        isCheckout ? global.events = [] : ''
        global.events.push(event)
      },
      recordCanvas: true, // 记录 canvas 内容
      checkoutEveryNms: 10 * 1000, // 每10s重新制作快照
      checkoutEveryNth: 200 // 每 200 个 event 重新制作快照
    })
  }
}